package uz.rt.utils;

import java.util.ArrayList;
import java.util.Iterator;

public class Volume<C extends Comparable<? super C>,
        D extends Comparable<? super D>,
        V extends Comparable<? super V>>
        implements Comparable<Volume<C, D, V>>, Iterable<Voxel<C, D, V>>
{
// ------------------------------ FIELDS ------------------------------

    final int sx;
    final int sy;
    final int sz;
    final ArrayList<Voxel<C, D, V>> data;

// --------------------------- CONSTRUCTORS ---------------------------

    public Volume(int sy, int sx, int sz) throws Exception
    {
        if (sx <= 0) throw new Exception("Dimension of x must be larger then 0.");
        if (sy <= 0) throw new Exception("Dimension of y must be larger then 0.");
        if (sz <= 0) throw new Exception("Dimension of z must be larger then 0.");
        this.sy = sy;
        this.sx = sx;
        this.sz = sz;
        data = new ArrayList<Voxel<C, D, V>>(sx * sy * sz);
        Coordinate<Integer> c = new Coordinate<Integer>(3);
        c.edit(0, 1);
        c.edit(1, 2);
        c.edit(2, 3);
        Dimension<Integer> d = new Dimension<Integer>(3);
        d.edit(0, 4);
        d.edit(1, 5);
        d.edit(2, 6);
        Voxel<Integer, Integer, Double> voxel = new Voxel<Integer, Integer, Double>();
        voxel.setCenter(c);
        voxel.setDimensions(d);
        voxel.setValue(10.5);
    }

// --------------------- GETTER / SETTER METHODS ---------------------

    public int getSx()
    {
        return sx;
    }

    public int getSy()
    {
        return sy;
    }

    public int getSz()
    {
        return sz;
    }

// ------------------------ INTERFACE METHODS ------------------------


// --------------------- Interface Comparable ---------------------

    public int compareTo(Volume<C, D, V> o)
    {
        if (size() != o.size()) return Integer.compare(size(), o.size());
        for (int i = 0; i < size(); i++)
            data.get(i).compareTo(o.data.get(i));
        return 0;
    }

// --------------------- Interface Iterable ---------------------

    public Iterator<Voxel<C, D, V>> iterator()
    {
        return data.iterator();
    }

// -------------------------- OTHER METHODS --------------------------

    public Voxel<C, D, V> get(int x, int y, int z)
    {
        return data.get(index(x, y, z));
    }

    public void set(int x, int y, int z, Voxel<C, D, V> voxel)
    {
        data.set(index(x, y, z), voxel);
    }

    private int index(int x, int y, int z)
    {
        if (x < 0) throw new IndexOutOfBoundsException("x index must be larger then 0");
        if (y < 0) throw new IndexOutOfBoundsException("y index must be larger then 0");
        if (z < 0) throw new IndexOutOfBoundsException("z index must be larger then 0");
        if (x >= this.sx) throw new IndexOutOfBoundsException("x index must not exceed sx dimensions");
        if (y >= this.sy) throw new IndexOutOfBoundsException("y index must not exceed sy dimensions");
        if (z >= this.sz) throw new IndexOutOfBoundsException("z index must not exceed sz dimensions");
        return z * (sx * sy) * x * sx + y;
    }

    public int size()
    {
        return data.size();
    }
}
